package com.cli.spring_distributed_lock.controller;


import com.cli.spring_distributed_lock.common.RedisLockHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.IntStream;

/**
 * @Author xiongmin
 * @Description //TODO
 * @Date 2020/4/5 16:10
 * @Version 1.0
 **/
@RestController
@Slf4j
public class RedisController {

    @Autowired
    RedisLockHelper redisLockHelper;

    private String REDIS_KEY_LOCK = UUID.randomUUID().toString();

    int surplusCount = 2;

    /**
     * 超时时间 5s
     */
    private static final int TIMEOUT = 5 * 1000;

    @RequestMapping(value = "/seckilling")
    public String Seckilling(String user) {
        //加锁
        long time = System.currentTimeMillis() + TIMEOUT;
        if (!redisLockHelper.lock(REDIS_KEY_LOCK, String.valueOf(time))) {
            log.info("排队人数太多，请稍后再试.");
            return "排队人数太多，请稍后再试.";
        }


        // 查询该商品库存，为0则活动结束 e.g. getStockByTargetId
        if (surplusCount == 0) {
            log.info("活动结束");
            return "活动结束.";
        } else {
            // 下单 e.g. buyStockByTargetId

            //减库存 不做处理的话，高并发下会出现超卖的情况，下单数，大于减库存的情况。虽然这里减了，但由于并发，减的库存还没存到map中去。新的并发拿到的是原来的库存
            surplusCount = surplusCount - 1;
            log.info("{} 抢到了商品，剩余{}", user, surplusCount);
            try {
                Thread.sleep(100);//模拟减库存的处理时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 减库存操作数据库 e.g. updateStockByTargetId

            // buyStockByTargetId 和 updateStockByTargetId 可以同步完成(或者事物)，保证原子性。
        }

        //解锁
        redisLockHelper.unlock(REDIS_KEY_LOCK, String.valueOf(time));

        return "恭喜您，秒杀成功。";
    }

    @GetMapping("/test")
    public List CompetitionForOrders() {

        //抢到商品的用户
        List<String> shopUsers = new ArrayList<>();

        //构造很多用户
        List<String> users = new ArrayList<>();
        IntStream.range(0, 100000).forEach(b -> {
            users.add("神牛-" + b);
        });

        //初始化库存
        surplusCount = 10;

        //模拟开抢
        users.parallelStream().forEach(b -> {
            if (surplusCount == 0) {
                return;
            }
            String responseInfo = Seckilling(b);
            if ("恭喜您，秒杀成功。".equals(responseInfo)) {
                shopUsers.add(b);
            }
        });

        return shopUsers;
    }

}
